#!/usr/bin/env python
import psgolftool, tohex

def test(binaryData, expectedPlaintext):
  plaintext = psgolftool.convert_unbinary(binaryData)
  if plaintext != expectedPlaintext:
    message = """binaryData = %s
plaintext = %s
expectedPlaintext = %s""" % (tohex.tohex(binaryData),
                             tohex.tohex(plaintext),
                             expectedPlaintext)
    raise message

def simple_tests():
  test('', '')
  test('0', '0')
  test('-1', '-1')
  test('100', '100')
  test('\x88\x00', '0')
  test('\x88\x64', '100')
  test('\x88\xf6', '-10')
  test('\x87\x80\x00', '128')
  test('\x85\xff\xff\xff\x7f', '36#zik0zj')
  test('\x85\x7f\xff\xff\xff', '-129')
  test('1 2', '1 2')
  test('1\t2', '1 2')
  test('1\n2', '1 2')
  test('_', '_')
  test('=only', '=only')
  test('1 = 2 =', '1 = 2 =')
  test('1 2\x92\x01', '1 2 add')
  test('\x92\x02', 'aload')
  test('\x92\x1b', 'counttomark')
  test('\x92\x3d', 'eq')
  test('\x91|', '/readhexstring')
  test('\x92|', 'readhexstring')
  test('/A', '/A')
  test('0/s()def', '0/s()def')
  test('\x92\xd9a', 'filter a')
  test('\x92\xd9()', 'filter()')
  test('. 0', '. 0')
  test('.1', '.1')
  test('-.1', '-.1')
  test('1.0', '1.0')
  test('-1.0', '-1.0')
  test('/ =', '/ =')
  test('1 2%3 4', '1 2')
  test('1 (2)%3 4\n=%\n=', '1(2)= =')
  test('<<>>', '<<>>')
  test('<<1 2>>', '<<1 2>>')
  test('[1 2>>', '[1 2>>')
  test('1\r\n2', '1 2') # Windows line endings.
  test('[', '[')
  test(']', ']')
  test('[]', '[]')
  test('{}', '{}')
  test('/ /', '/ /')
  test('/_ /', '/_/')
  test('/!/ /!', '/!/ /!')
  test('[>>\x92\x0d', '[>>begin')

def radix_tests():
  test('2#100', '4')
  test('1#100', '1#100')
  test('36#Z', '35')
  test('36#zzzzzz', '36#zzzzzz')
  test('36#012345', '1776965')
  test('37#z', '37#z')
  test('10#4294967290', '-6')

def string_tests():
  test('()', '()')
  test('(\))', '(\))')
  test('\x8e\x01)', r'(\))')
  test('\x8e\x01\\', r'(\\)')
  test('(\x00)', '<0>')
  test('\x8e\x02\x00-', r'(\0-)')
  test(r'(\0)', '<0>')
  test('\x8e\x02\x08-', r'(\b-)')
  test(r'(\b)', r'(\b)')
  test('\x8e\x02\x0c-', r'(\f-)')
  test(r'(\f)', r'(\f)')
  test('\x8e\x01\x09', '(\t)')
  test('(\t)', '(\t)')
  test(r'(\t)', '(\t)')
  test('\x8e\x01\x0a', '(\n)')
  test('(\n)', '(\n)')
  test(r'(\n)', '(\n)')
  test('\x8e\x05\x0b----', r'(\13----)')
  test(r'(\13----)', r'(\13----)')
  test('\x8e\x03\x0d--', r'(\r--)')
  test('(\r--)', '(\n--)') # \r is converted to \n
  test(r'(\r--)', r'(\r--)')
  test('\x8e\x01\r', r'(\r)')

  test(r'(\\t--)', r'(\\t--)')
  test('\x8e\x01\x7f', r'<7f>')
  test('\x8e\x09\x7f--------', r'(\177--------)')
  test('\x8e\x02()', r'(())')
  test('\x8e\x03(()', r'((\())')
  test('\x8e\x0a\x0000000000', r'(\00000000000)')
  test(r'(\00000000000)', r'(\00000000000)')
  test(r'(\0\088888)', r'(\0\088888)')
  test('\x8e\x02\x008', r'(\08)')
  test('(a)(a)eq', '(a)(a)eq')
  test(r'(\0008)', r'(\08)')
  test(r'(\000\000)', r'<000>')
  test(r'(\0000)', '<003>')
  test('(())', '(())')
  test('((\)))', '(()\))')
  test(r'(\)\()=', '(\)\()=')
  test(r'(\(\)\()', r'(()\()')

  test('<>', '()')
  test('<0d>', r'(\r)')
  test('<0d2>', r'(\r )')
  test('<31>', '(1)')
  test('<90>', '<9>')
  test('<9>', '<9>')

  test('<~~>=', '()=')
  test('<~~=', '()=')
  test('<~z~=', '<~z~=')
  test('<~"!~=', r'(\3)=')
  test('<~\0!\t!\n!\x0c! !~=', '<~z~=')

  test('(\0\0\0\0)=', '<~z~=')
  test('(\377\377\377\377)=', '<~s8W-!~=')
  test('(/:\2\243)=', '<~00000~=')
  test('<031c84b1>=', '<~"!!!!~=')
  test('(\0\0\0\0\0)=', '<~z!!~=')
  test('<0123456789abcdef>=', '<~!@($GM6"ni~=')

  test('<~hello!!~=', '<~hello!!~=')
  test('<~z!!~=', '<~z!!~=')
  test('<~!!!!!z~=', '<~zz~=')
  test('<~!@($GM6"ni~=', '<~!@($GM6"ni~=')
  test('<~s8W-!~==', '<~s8W-!~==')
  #test('<~s8W-"~==', None)

def homogeneous_array_tests():
  test('\x95\x00\x00\x01\x12\x34\x56\x78', '{305419896}') # 32-bit, high byte first.
  test('\x95\x20\x00\x02\x12\x34\x56\x78', '{4660 22136}') # 16-bit, high byte first.
  test('\x95\x80\x01\x00\x12\x34\x56\x78', '{36#xe0d1u}') # 32-bit, low byte first.
  test('\x95\xa0\x02\x00\x12\x34\x56\x78', '{13330 30806}') # 16-bit, low byte first.
  test('\x95\x00\x00\x01\xff\xff\xff\xff', '{-1}')
  test('\x95\x20\x00\x01\xff\xff', '{-1}')

def complex_tests():
  binarydata = '\x88\x7f{/s\x8e\x06%stdin\x8e\x01r\x92A\x88\x1e\x92\xa5\x92}{\x923s\x8e\x01?\x92\x8d2\x92X0\x8801\x889{\x92xs\x92b\x88\x0f\x92P{1\x88\x01s{2\x92X\x92l\x92\x01\x92>2\x92\xc1\x92>}\x92I\x88\n}{\x88\x0e0 s{\x88\x1e\x92j2\x92X\x92l\x92\x01\x92>1\x92\xa9\x92>}\x92I\x88\x0b}\x92U\x92j3\x92={s =}\x92T\x92u2\x92X0}\x92H}\x92T}\x92\x83'
  plaintext = '127{/s(%stdin)(r)file 30 string readline{def s(?)search 2 index 0 48 1 57{put s length 15 gt{1 1 s{2 index mul add exch 2 xor exch}forall 10}{14 0 s{30 mod 2 index mul add exch 1 sub exch}forall 11}ifelse mod 3 eq{s =}if pop 2 index 0}for}if}repeat'
  test(binarydata, plaintext)

  binarydata = '0\x88\xfe1/s(%stdin)(r)\x92A\x87\xe9\x03\x92\xa5\x92}\x92u\x923s\x92b1\x92\xa9{s\x92>3{\x92L{1\x92\x04\x92\x012\x92l}\x92I\x92n8\x92\x40\x92m{\x92\xa2}\x92T( )}\x92\xa3{(#)}\x92T\x92v0}\x92H'
  plaintext = '0 -2 1/s(%stdin)(r)file 1001 string readline pop def s length 1 sub{s exch 3{getinterval{1 and add 2 mul}forall neg 8 exit ne{stop}if( )}stopped{(#)}if print 0}for'
  test(binarydata, plaintext)

  #binarydata='\x92\x1f/zlibDecode\x92\xd9\x922\x92?x\x9c]\x8fA\n\xc20\x14DQ\x97^"7\xf8\xe8\xaa\x9b\x1c\xc0\x1b\x14\xc4]\xa7&P~ M\xd2\xd6\xe2\xdeU\x17\xff\xc4\xfe\x16Ep3\x0c3\xcc\x83\xa1\x07b0\xf6J\x81Ai\x08\x94\\\x04\xa8\r9R\xeb\x0b\xa8\xf7#\xf5(`\x82\xbf\xbbD\xec\x197\xa9f\xfb\x94\x0b%\xb0\xb1\x84n\xed\xd5\xa4\x01]\xc1JS\xc7\xaa\xce\xc7/\xaa\xfd#\xfd@\x81\xbbII+A\x99\xb2\x97\xac\xf1YwQ\xc6Y\xaaO?\x19\xfb\xdaI=\x9f\xa4\xde\x92\xe5\xa0\x91\x94m\x92U\x96\xa3>0.s\x13\xd1\xd8'
  #plaintext = '0 -2 1/s(%stdin)(r)file 1001 string readline pop def s length 1 sub{s exch 3{getinterval{1 and add 2 mul}forall neg 8 exit ne{stop}if( )}stopped{(#)}if print 0}for'
  #test(binarydata, plaintext)

def main():
  simple_tests()
  radix_tests()
  string_tests()
  homogeneous_array_tests()
  complex_tests()

if __name__ == '__main__':
  main()
